/******************************************************************************
	This file is a part of the Snapshot Bioinformatics Project

	Copyright (C) 2012-2013 Jarom Schow

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

#include "AppMain.h"

#include <QtCore/QDateTime>
#include <QtCore/QDir>
#include <QtCore/QSettings>

#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>

#include "Core.h"
#include "LogFile.h"
#include "Progress.h"

#include "AppSettings.h"
#include "ProgressMgr.h"

// Platform-specific
#if defined(Q_OS_WIN)
#include <eh.h>
#include <shlobj.h>
#elif defined(Q_OS_MAC)
#include <dlfcn.h>
#include <dirent.h>
#include <mach-o/dyld.h>

#include <sys/param.h>
#include <crt_externs.h>
#include <Carbon/Carbon.h>
// Apparently this function is supplied by the Qt libraries, 
// but not declared in a header, so declare it here.
void qt_set_sequence_auto_mnemonic( bool on );
#define MAX_PATH 512
#endif

const QString	c_tempFolderName( "/Temp" );

/**
**/
AppMain::AppMain( int argc, char **argv, const QString &appName, const Bio::Version &version ) : m_version( version )
{
	m_app = new QApplication( argc, argv );
	m_app->setApplicationName( appName );
	m_app->setOrganizationName( "Bio" );
	m_app->setApplicationVersion( m_version.getVersionString() );

#if defined(Q_OS_WIN)
	m_app->addLibraryPath( m_app->applicationDirPath() + "/plugins/" );
#elif defined(Q_OS_MAC)
	m_app->addLibraryPath( m_app->applicationDirPath() + "/../PlugIns/" );
#else
	#error "No code implementation on this platform"
#endif

	setAppDataPath();

	QSettings::Format	format = QSettings::registerFormat( "settings", AppSettings::read, AppSettings::write );

	//QSettings::setPath( format, QSettings::UserScope, m_appDataPath );
	QSettings::setDefaultFormat( format );

	Bio::Core::setMessageHandler( new Bio::LogFile( m_appDataPath + "/log.txt" ) );

	Bio::Core::log( "================================================================================" );
	Bio::Core::log( QString( "%1 started at: %2" ).arg( m_app->applicationName() ).arg( QDateTime::currentDateTime().toString() ) );
	Bio::Core::log( QString( "SQL Drivers:" ) + QSqlDatabase::drivers().join( ',' ) );
}

/**
**/
AppMain::~AppMain()
{
	Bio::Core::log( QString( "%1 exited at: %2" ).arg( m_app->applicationName() ).arg( QDateTime::currentDateTime().toString() ) );

	delete m_app;
}

/**
**/
int AppMain::exec()
{
	Bio::Progress::setProgressHandler( new ProgressMgr( getMainWindow(), m_app->applicationName() ) );

	int result = m_app->exec();

	Bio::Progress::setProgressHandler( NULL );

	return result;
}

/**
**/
QString AppMain::getAppDataPath() const
{
	return m_appDataPath;
}

/**
**/
QString AppMain::getTempPath() const
{
	return m_appDataPath + c_tempFolderName;
}

/**
**/
void AppMain::showURL( const QString &url ) const
{
	if( url.isEmpty() )
		return;

#if defined(Q_OS_WIN)
	// Use ShellExecuteA to explicitly specify ASCII URL.
	HINSTANCE status = ::ShellExecuteA( NULL, "open",
		url.toLatin1(), NULL, NULL, SW_SHOWNORMAL );
#elif defined(Q_OS_MAC)
	// the "new & improved" OSX Carbon API call using Launch Services:
	QByteArray urlAscii = url.toLatin1();
	CFURLRef toOpen = CFURLCreateWithBytes( NULL, (const UInt8*) urlAscii.constData(), url.length(), 0, NULL );
	OSStatus err = LSOpenCFURLRef( toOpen, NULL );
	CFRelease( toOpen );
#else
	#error "No code implementation on this platform"
#endif
}

/**
**/
Bio::Version AppMain::getVersion() const
{
	return m_version;
}

/**
**/
void AppMain::setAppDataPath()
{
#ifdef Q_OS_WIN
	PWSTR	path;

	if( SHGetKnownFolderPath( FOLDERID_RoamingAppData, 0, NULL, &path ) == S_OK ){
		m_appDataPath = QString::fromUtf16( reinterpret_cast<ushort*>( path ) );
		m_appDataPath.replace( "\\", "/" );
		m_appDataPath += "/" + m_app->organizationName() + "/" + m_app->applicationName();
	}
	else
		m_appDataPath = m_app->applicationDirPath();
#elif defined Q_OS_MAC
	FSRef	found;
	char	buffer[MAX_PATH];

	::FSFindFolder( kUserDomain, kApplicationSupportFolderType, kDontCreateFolder, &found );
	::FSRefMakePath( &found, (UInt8*)buffer, MAX_PATH );
	m_appDataPath = buffer;
	m_appDataPath += "/" + m_app->organizationName() + "/" + m_app->applicationName();
#else
	m_appDataPath = m_app->applicationDirPath();
#endif

	QDir dataDir( m_appDataPath );

	if( !dataDir.exists() )
		dataDir.mkpath( m_appDataPath );

	if( !dataDir.exists( m_appDataPath + c_tempFolderName ) )
		dataDir.mkpath( m_appDataPath + c_tempFolderName );
}
